﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Xml;
using System.ServiceModel.Syndication;
using System.IO;
using System.Xml.Schema;
using System.ServiceModel.Web;
using System.ServiceModel.Channels;


namespace dasBlog.Storage
{
    [ServiceBehavior(ConfigurationName = "StreamStorageNode", InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
    internal sealed class StreamStorageNodeService : IStreamStorageNode
    {
        private IStreamStorageProvider _streamProvider;

        public StreamStorageNodeService(IStreamStorageProvider provider)
        {
            _streamProvider = provider;
        }

        public Message GetItemSchema(string baseUri, string schemaId)
        {
            var replyAction = Names.IStorageNodeNamespace+"GetItemSchemaResponse";
            XmlSchema schema = SerializationTools<StreamStorageInfo>.GetSchema(baseUri, schemaId);
            if (schema != null)
            {
                return Message.CreateMessage(
                                GetReplyMessageVersion(),
                                replyAction,
                                new XmlSchemaBodyWriter(schema));
            }
            else
            {
                return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction);
            }
        }

        public StreamStorageGetReply GetStream(StreamStorageGetRequest getRequest)
        {
            return _streamProvider.GetStream(getRequest);
        }

        public StreamStorageSetReply SetStream(StreamStorageSetRequest addRequest)
        {
            return _streamProvider.SetStream(addRequest);
        }


        public Message Select(string baseUri, Moniker moniker, MonikerMatch contextMatch, QueryDescription query, SerializationMode serializationMode)
        {
            var replyAction = Names.IStorageNodeNamespace+"SelectResponse";
            var result = _streamProvider.Select(moniker, contextMatch, query);
            if (result == null || result.Count() == 0)
            {
                return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction);
            }
            else
            {
                if (serializationMode == SerializationMode.Rss || serializationMode == SerializationMode.Atom)
                {
                    List<SyndicationItem> items = new List<SyndicationItem>();
                    foreach (SyndicationItem item in from StreamStorageInfo t in result select t.ToSyndicationItem<StreamStorageInfo>())
                    {
                        List<SyndicationLink> links = new List<SyndicationLink>();
                        foreach (SyndicationLink link in item.Links)
                        {
                            if (link.Uri.Scheme == Moniker.Scheme)
                            {
                                links.Add(
                                    new SyndicationLink(
                                        new Moniker(link.Uri).ToUri(new Uri(baseUri)),
                                        link.RelationshipType,
                                        link.Title,
                                        link.MediaType,
                                        link.Length));
                            }
                        }
                        item.Links.Clear();
                        foreach (var link in links)
                        {
                            item.Links.Add(link);
                        }
                        items.Add(item);
                    }

                    var feed = new SyndicationFeed(items);
                   
                    if (serializationMode == SerializationMode.Rss)
                    {
                        return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction,
                                        new SyndicationFeedBodyWriter(
                                            new Rss20FeedFormatter<SyndicationFeed>(feed)));
                    }
                    else
                    {
                        return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction,
                                        new SyndicationFeedBodyWriter(
                                            new Atom10FeedFormatter<SyndicationFeed>(feed)));
                    }
                }
                else
                {
                    return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction,
                                        SerializationTools<StreamStorageInfo>.ToBodyWriter(result.ToArray(), serializationMode == SerializationMode.Json ? WebMessageFormat.Json : WebMessageFormat.Xml));
                }
            }
        }

        public Message Get(string baseUri, Moniker itemId, SerializationMode serializationMode)
        {
            var replyAction = Names.IStorageNodeNamespace+"GetResponse";
            var item = _streamProvider.Get(itemId);
            if (item != null)
            {
                return Message.CreateMessage(
                    GetReplyMessageVersion(),
                    replyAction,
                    SerializationTools<StreamStorageInfo>.ToBodyWriter(item, serializationMode == SerializationMode.Json ? WebMessageFormat.Json : WebMessageFormat.Xml));
            }
            else
            {
                return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction);
            }
        }

        private static MessageVersion GetReplyMessageVersion()
        {
            if (OperationContext.Current != null)
            {
                return OperationContext.Current.IncomingMessageVersion;
            }
            else
            {
                return MessageVersion.Default;
            }
        }

        public void Delete(Moniker itemId)
        {
            _streamProvider.Delete(itemId);
        }

        public Moniker Store(Moniker moniker, XmlElement xitem, SerializationMode serializationMode)
        {
            return _streamProvider.Store(moniker, SerializationTools<StreamStorageInfo>.Deserialize(new XmlNodeReader(xitem), serializationMode == SerializationMode.Json ? WebMessageFormat.Json : WebMessageFormat.Xml));
        }

        public Message Aggregate(string baseUri, Moniker moniker, MonikerMatch match, string propertyName, SerializationMode serializationMode)
        {
            var replyAction = Names.IStorageNodeNamespace+"AggregateResponse";
            var result = _streamProvider.Aggregate(moniker, match, propertyName);
            if (result == null || result.Count() == 0)
            {
                return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction);
            }
            else
            {
                if (serializationMode == SerializationMode.Rss || serializationMode == SerializationMode.Atom)
                {
                    var feed = new SyndicationFeed(from PropertyAggregate prop in result select new SyndicationItem{ Title = TextSyndicationContent.CreatePlaintextContent(prop.Value), Content = TextSyndicationContent.CreatePlaintextContent(prop.Count.ToString()) });
                    if (serializationMode == SerializationMode.Rss)
                    {
                        return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction,
                                        new SyndicationFeedBodyWriter(
                                            new Rss20FeedFormatter<SyndicationFeed>(feed)));
                    }
                    else
                    {
                        return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction,
                                        new SyndicationFeedBodyWriter(
                                            new Atom10FeedFormatter<SyndicationFeed>(feed)));
                    }

                    
                    
                }
                else
                {
                    return Message.CreateMessage(
                                        GetReplyMessageVersion(),
                                        replyAction,
                                        SerializationTools<PropertyAggregate>.ToBodyWriter(result.ToArray(), serializationMode == SerializationMode.Json ? WebMessageFormat.Json : WebMessageFormat.Xml));

                }
            }
        }

    }
}
